package game.gamestorage.texas.db;

import java.util.ArrayList;

import util.DebugOut;

import game.Action;
import game.model.Card;

/**
 * This class is the "middle" part of the mapping form Java to database</br>
 * Responsable for writing to db
 * 
 * the annotation "@category" is used to group methods to higher level methods in</br>
 * game.gamestorage.IF_SetGameStorage and</br>
 * game.gamestorage.texas.IF_SetGameStorageTH
 * 
 * @author Witthold/Korol
 */
public class SetterDBProjector extends DBProjector {

	/** IDs per competition: inherit from super */
	/** hand depending fields */
	private int hand_id;
	private int round_id;
	private int[] hand_player_map_ids;


	/**
	 * writes gamedef
	 * @category _0 Prequisites<br>
	 *           
	 * @param limited - limited:1; pot-limit:0; no-limit: -1
	 * @param minBet - only int possible
	 * @param maxBet - only int possible
	 * @param numPlayers - amount of participating players
	 * @param style - cashgame:1; tournament:2; doyle:3;
	 * @param buyin - only int possible
	 * 
	 * @return true, if writing to db succeeded
	 */
	public boolean setGameDef(int limited, int minBet, int maxBet, int numPlayers, int style, int buyin) {
		gamedef_id = SetterQueryExecution.registerGameDef(limited, minBet, maxBet, numPlayers, style, buyin);
		if (gamedef_id > 0) {
			return true;
		}
		return false;
	}


	/**
	 * writes competition
	 * @category _1 setStartCompetition<br>
	 *           
	 * @return true, if writing to db succeeded
	 */
	public boolean setCompetition() {
		competition_id = SetterQueryExecution.registerCompetition(gamedef_id);
		if (competition_id > 0) {
			return true;
		}
		return false;
	}


	/**
	 * writes player - if not already existing
	 * @category _1 setStartCompetition<br>
	 *           
	 * @param player_names - all participants as String[] -
	 * 
	 * @return true, if writing to db succeeded
	 */
	public boolean setPlayers(String[] player_names) {
		player_ids = SetterQueryExecution.registerPlayers(player_names);
		for (int id : player_ids) {
			if (id < 1) {
				return false;
			}
		}
		return true;
	}


	/**
	 * writes competition_player_map
	 * @category _1 setStartCompetition<br>
	 *           
	 * @param cash_init - with how much credits do the players start this? -
	 * 
	 * @return true, if writing to db succeeded
	 */
	public boolean setCompetitionPlayerMap(int[] cash_init) {
		if (SetterQueryExecution.registerCompetitionPlayerMap(player_ids, cash_init, competition_id)) {
			return true;
		}
		return false;
	}


	/**
	 * writes hand
	 * @category _2 setHand<br>
	 *           
	 * @param sb - smallblind
	 * @param bb - bigblind
	 * @param ante - forced bet for all players
	 * 
	 * @return true, if writing to db succeeded
	 */
	public boolean setHand(int sb, int bb, int ante) {
		hand_id = SetterQueryExecution.registerHand(sb, bb, ante, competition_id);
		if (hand_id > 0) {
			return true;
		}
		return false;
	}


	/**
	 * writes hand_player_map
	 * @category _2 setHand<br>
	 *           
	 * @param position
	 * 			Position of the player in this hand
	 * 			(0: first player behind the button; 1: second player behind the button; ...)
	 * @param cash_init - with how much credits do the players start this? - starting credits of every player
	 * @return true, if writing to db succeeded
	 */
	public boolean setHandPlayerMap(int[] position, int[] cash_init) {

		hand_player_map_ids = SetterQueryExecution.registerHandPlayerMap(position, cash_init, player_ids, hand_id);
		int h = 0, p = 0;

		for (int i = 0; i < hand_player_map_ids.length; i++) {
			if (hand_player_map_ids[i] > -1) {
				h++;
			}
			if (position[i] > -1) {
				p++;
			}
		}
		if (h == p) {
			return true;
		}
		return false;
	}


	/**
	 * @category _2
	 *           setHand<br>
	 *           writes card_of_player (only bots own)
	 * @param holeCards - players holeCards as Card[]
	 * @return true, if writing to db succeeded
	 */
	public boolean setCardOfPlayer(Card[] holeCards) {
		for (Card card : holeCards) {
			if (!SetterQueryExecution.registerCardOfPlayer(card.toInt(), hand_player_map_ids[0])) {
				return false;
			}
		}
		return true;
	}


	/**
	 * @category _3
	 *           setEndRound<br>
	 *           writes a*bet, one round
	 * @param timestamp as unix timestamp
	 * @param betHistory - all bets of this round
	 * @return true, if writing to db succeeded
	 */
	public boolean setBetHistory(long timestamp, ArrayList<Action> betHistory) {

		/* registerRound */
		round_id = SetterQueryExecution.registerRound(hand_id, timestamp);

		if (round_id < 1) {
			return false;
		}

		/* registerBets */
		if (!SetterQueryExecution.registerBets(betHistory, round_id, player_ids)) {
			return false;
		}

		return true;
	}


	/**
	 * @category _3
	 *           setEndRound<br>
	 *           writes card_common<br>
	 * @param revealedBoardCards (if revealed)
	 * @return true, if writing to db succeeded
	 */
	public boolean setCommonCards(Card[] revealedBoardCards) {

		if (revealedBoardCards != null) {

			int[] cardValues = new int[revealedBoardCards.length];

			for (int i = 0; i < revealedBoardCards.length; i++) {
				cardValues[i] = revealedBoardCards[i].toInt();
			}

			if (cardValues.length == 0) {
				return true;
			}

			if (!SetterQueryExecution.registerCommonCards(cardValues, round_id)) {
				return false;
			}
		}

		return true;
	}


	/**
	 * @category _4
	 *           setEndHand<br>
	 *           writes card_of_player (enemyCards, if available)
	 * @param enemyCards - if cards were shown
	 * @return true, if writing to db succeeded
	 */
	public boolean setHoleCards(Card[][] enemyCards) {

		for (int i = 1; i < enemyCards.length; i++) {
			if (enemyCards[i] != null) {
				for (Card card : enemyCards[i]) {
					if (!SetterQueryExecution.registerCardOfPlayer(card.toInt(), hand_player_map_ids[i])) {
						return false;
					}
				}
				DebugOut.showVerboseSql("setEnemyCards for hand_player_map_id: " + hand_player_map_ids[i]);
			} else {
				DebugOut.showVerboseSql("setEnemyCards: @i is null - das Schwein hat nix gezeigt");
			}
		}
		return true;
	}


	/**
	 * @category _4
	 *           setEndHand<br>
	 *           writes finalpot into hand
	 * @param finalpot - total at the end of the hand
	 * @return true, if writing to db succeeded
	 */
	public boolean setFinalPot(int finalpot) {
		if (SetterQueryExecution.registerFinalPot(finalpot, hand_id)) {
			return true;
		}
		return false;
	}


	/**
	 * @category _4
	 *           setEndHand<br>
	 *           updates hand_player_map
	 * @param cash_delta - diff between before and after played hand
	 * @return true, if writing to db succeeded
	 */
	public boolean setCashDeltas(int[] cash_delta) {
		for (int i = 0; i < cash_delta.length; i++) {
			if (!SetterQueryExecution.registerCashDelta(cash_delta[i], player_ids[i], hand_id)) {
				return false;
			}
		}
		return true;
	}


	/**
	 * @category _5
	 *           setEndCompetition<br>
	 *           updates competition_player_map
	 * @param ranking of all participants
	 * @return true, if writing to db succeeded
	 */
	public boolean setRankings(int[] ranking) {
		for (int i = 0; i < ranking.length; i++) {
			if (!SetterQueryExecution.registerRank(ranking[i], player_ids[i], competition_id)) {
				return false;
			}
		}
		return true;
	}


	/*
	 * Getters
	 */
	/**
	 * @return the hand_id generated by db
	 */
	public int getHand_id() {
		return hand_id;
	}


	/**
	 * @return the hand_player_map_ids generated by db
	 */
	public int[] getHandPlayerMap_ids() {
		return hand_player_map_ids;
	}


	/*
	 * Misc
	 */
	/**
	 * @return true, if there is at least one connection to the db
	 */
	public boolean connectionSuccess() {

		return SetterQueryExecution.connectionSuccess();
	}
}
